using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ReinforcementLearning
{
    public class QTable
    {
        private int numberOfStates; // O numero de estados por coluna
        private int numberOfActions; //O numero de acoes por linha
        private ActionValue [,] table;
        private string filePath;
        
        public QTable()
        {
            this.numberOfActions = Enum.GetValues(typeof(Action)).Length - 1; //remove o undefined da lista
            this.numberOfStates = Enum.GetValues(typeof(State)).Length - 1; //remove o undefined da lista
            this.table = new ActionValue[this.numberOfStates, this.numberOfActions];
            this.filePath = @"knowledgeBase/SimpleTestActionValueTable.rlkb";
            this.loadLearnedData();
        }


        public int NumberOfStates
        {
            get { return this.numberOfStates; }
        }

        public int NumberOfActions
        {
            get { return this.numberOfActions; }
        }
        
        private void loadLearnedData()
        {
            this.createAfileIfDontExist();

            StreamReader readerActionValue = File.OpenText(this.filePath);
            for (int i = 0; i < this.numberOfStates; i++)
            {
                string actionValueLine = readerActionValue.ReadLine();
                if (actionValueLine != null)
                {
                    char[] spliters = { ';', ' '};
                    string [] splited = actionValueLine.Split(spliters);
                    int indexInsplited = 0;
                    for (int j = 0; j < this.numberOfActions; j++)
                    {
                        double value = Double.Parse(splited[indexInsplited]);
                        int numberOfVisits = Int32.Parse(splited[indexInsplited+1]);
                        indexInsplited += 2;
                        ActionValue actionValue = new ActionValue(value,numberOfVisits);
                        this.table[i, j] = actionValue;
                    }
                }
            }
            readerActionValue.Close();
        }

        private void createAfileIfDontExist()
        {
            FileInfo fileInfo = new FileInfo(this.filePath);
            if (!fileInfo.Exists)
            {
                StreamWriter writer = fileInfo.CreateText();
                for (int i = 0; i < this.numberOfStates; i++)
                {
                    string row = "";
                    for (int j = 0; j < this.numberOfActions; j++)
                    {
                        row = row + " " + 0 + ";" + 0;
                    }
                    writer.WriteLine(row.TrimStart());
                }
                writer.Close();
            }
        }

        public void setValue(State state, Action action, double value)
        {
            this.table[(int)state, (int)action].value = value;
        }

        public void incrementNumberOfVisits(State state, Action action)
        {
            this.table[(int)state, (int)action].numberOfVisits++;
        }

        public ActionValue getActionValue (State state, Action action)
        {
            return this.table[(int)state, (int)action];
        }

        public void saveLearnedData()
        {
            FileInfo fileInfo = new FileInfo(this.filePath);
            StreamWriter writer = fileInfo.CreateText();
            for (int i = 0; i < this.numberOfStates; i++)
            {
                string row = "";
                for (int j = 0; j < this.numberOfActions; j++)
                {
                    row = row + " " + this.table[i,j].value + ";" + this.table[i,j].numberOfVisits;
                }
                writer.WriteLine(row.TrimStart());
            }
            writer.Close();   
        }


        public Action converIntToAction(int value)
        {
            Action action = Action.UNDEFINED;
            string name = Enum.GetName(typeof(Action), value);
            action = (Action)Enum.Parse(typeof(Action), name);
            return action;
        }

        public State convertIntToState(int value)
        {
            State state = State.UNDEFINED;
            string name = Enum.GetName(typeof(State), value);
            state = (State)Enum.Parse(typeof(State), name);
            return state;
        }

        public static List<Action> getAllActions()
        {
            List<Action> actions = new List<Action>();
            foreach (string name in Enum.GetNames(typeof(Action)))
            {
                actions.Add((Action)Enum.Parse(typeof(Action), name));
            }

            return actions;
        }
    }
}
